#!/usr/bin/env python
# -*- coding: utf8 -*-
import codecs
import json
import logging
import os.path
import re
import subprocess
import sys
import random
import time
from collections import defaultdict
from functools import partial

import qdarkstyle
import requests
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from libs.constants import *
from libs.ustr import ustr
from PyQt5 import QtCore, QtGui, QtWidgets

from libs import HashableQListWidgetItem
from libs import RemoteDialog
from libs.canvas import Canvas
from libs.colorDialog import ColorDialog
from libs.labelDialog import LabelDialog
from libs.labelFile import LabelFile, LabelFileError
from libs.lib import struct, newAction, newIcon, addActions, fmtShortcut
from libs.appsettings import APPSettings
from libs.pascal_voc_io import PascalVocReader
from libs.shape import Shape, DEFAULT_LINE_COLOR, DEFAULT_FILL_COLOR
from libs.toolBar import ToolBar
from libs.zoomWidget import ZoomWidget
from libs.ImageManagement import loadImageThread, loadOnlineImgMul
from libs.SettingDialog import SettingDialog
from libs.save_mask_image import label_mask_writer
from libs.LoginDialog import SignInDialog
from libs.DBManager import DBManager
import time

__appname__ = 'labelImgPlus'


# Utility functions and classes.
def have_qstring():
    '''p3/qt5 get rid of QString wrapper as py3 has native unicode str type'''
    return not (sys.version_info.major >= 3 or QT_VERSION_STR.startswith('5.'))


def util_qt_strlistclass():
    return QStringList if have_qstring() else list

class myPoint():
    def __init__(self, key, value):
        self.key = key
        self.value = value
        pass

class myLine():
    def __init__(self, key, value):
        self.key = key
        self.value = value
        pass

class Image():    
    def __init__(self, path, img):
        self.path = path
        self.points = []
        self.image = img
        self.lineToPoint = []

class WindowMixin(object):

    def menu(self, title, actions=None):
        menu = self.menuBar().addMenu(title)
        if actions:
            addActions(menu, actions)
        return menu

    def toolbar(self, title, actions=None):
        toolbar = ToolBar(title)
        toolbar.setObjectName(u'%sToolBar' % title)
        # toolbar.setOrientation(Qt.Vertical)
        toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        if actions:
            addActions(toolbar, actions)
        self.addToolBar(Qt.LeftToolBarArea, toolbar)
        return toolbar


class MainWindow(QMainWindow, WindowMixin):
    FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = range(3)
    
    pyqt_connect = pyqtSignal()
    
    def __init__(self, filename=None):
        super(MainWindow, self).__init__()
        self.db = DBManager()
        self.db.setup()
        self.setWindowTitle(__appname__)

        # info display
        self.pixmap = QPixmap()
        self.display_timer = QTimer()
        self.display_timer.start(1000)
        self.pyqt_connect.connect(
            self.info_display)
        # online database
        self.database_url = None
        self.connect_remote_db = None
        self.dowload_thread_num = 4
        self.server_image_num = 0
        self.dowload_image_num = 0
        self.process_image_num = 0
        self.server_image_list = None
        self.editing = False
         # label color map
        self.label_font_size = 10

        # Save as Pascal voc xml
        self.defaultSaveDir = None
        self.usingPascalVocFormat = True
        if self.usingPascalVocFormat:
            LabelFile.suffix = '.xml'
        # For loading all image under a directory
        self.mImgList = []
        self.Images = {} # 存储每张图片的属性
        self.dirname = None
        self.image_size = []
        self.labelHist = []
        self.label_fre_dic = {}
        self.label_sub_dic = {}
        self.label_num_dic = {}
        self.lastOpenDir = None
        date = time.strftime('%Y_%m_%d_%H', time.localtime(time.time()))
        self.loadFilePath = 'database/pics/' + date + '/'

        # Whether we need to save or not.
        self.dirty = False

        # Enble auto saving if pressing next
        self.autoSaving = True
        self._noSelectionSlot = False
        self._beginner = True
        self.screencastViewer = "firefox"

        self.label_color_list = QListWidget()
        # Main widgets and related state.
        self.labelDialog = LabelDialog(parent=self, listItem=self.labelHist)
        self.pointList = QListWidget()
        self.itemsToShapes = {} # 点 -> 点集合索引
        self.shapesToItems = {}

        self.pointList.itemActivated.connect(self.pointSelectionChanged)
        self.pointList.itemSelectionChanged.connect(self.pointSelectionChanged)
        self.pointList.itemDoubleClicked.connect(self.editLabel)
        #禁止双击可编辑	
        self.pointList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        #右键菜单
        self.pointList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.pointList.customContextMenuRequested.connect(self.myListWidgetContext)

        # Connect to itemChanged to detect checkbox changes.
        self.pointList.itemChanged.connect(self.labelItemChanged)

        listLayout = QVBoxLayout()
        listLayout.setContentsMargins(0, 0, 0, 0)
        listLayout.addWidget(self.pointList)
        self.editButton = QToolButton()
        self.editButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.pointListContainer = QWidget()
        self.pointListContainer.setLayout(listLayout)
        self.info_txt = QTextEdit()

        #listLayout.addWidget(self.editButton)  # , 0, Qt.AlignCenter)
        listLayout.addWidget(self.pointList)
        #listLayout.addWidget(self.info_txt)

        self.dock = QDockWidget(u'点标签', self)
        self.dock.setObjectName(u'Labels')
        self.dock.setWidget(self.pointListContainer)
        # add file list add dock to move faster
        self.fileListWidget = QListWidget()
        self.fileListWidget.itemDoubleClicked.connect(
            self.fileitemDoubleClicked)
        filelistLayout = QVBoxLayout()
        filelistLayout.setContentsMargins(0, 0, 0, 0)
        filelistLayout.addWidget(self.fileListWidget)
        #self.fileListContainer = QWidget()
        #self.fileListContainer.setLayout(filelistLayout)
        #self.filedock = QDockWidget(u'文件列表', self)
        #self.filedock.setObjectName(u'Files')
        #self.filedock.setWidget(self.fileListContainer)

        # select a label
        self.pointListWidget = QListWidget()
        self.pointListWidget.itemDoubleClicked.connect(
            self.labelitemDoubleClicked)
        pointListLayout = QVBoxLayout()
        pointListLayout.setContentsMargins(0, 0, 0, 0)
        pointListLayout.addWidget(self.pointListWidget)
        self.pointListContainer = QWidget()
        self.pointListContainer.setLayout(pointListLayout)
        
        #self.labelSelectDock = QDockWidget(u'选择标签', self)
        #self.labelSelectDock.setObjectName(u'selectLabel')
        #self.labelSelectDock.setFeatures(QDockWidget.DockWidgetFloatable |
        #         QDockWidget.DockWidgetMovable)
        #self.labelSelectDock.setWidget(self.pointListContainer)
        #if self.task_mode != 2:
        #    self.labelSelectDock.setEnabled(False)
        
        # label color map dock
        self.label_color_list.itemDoubleClicked.connect(
            self.labelColorDoubleClicked
        )
        self.loadPredefinedDETClasses()
        label_color_layout = QVBoxLayout()
        label_color_layout.setContentsMargins(0, 0, 0, 0)
        label_color_layout.addWidget(self.label_color_list)
        self.label_color_container = QWidget()
        self.label_color_container.setLayout(label_color_layout)
        #self.label_color_dock = QDockWidget(u'Label Color Map', self)
        #self.label_color_dock.setObjectName(u'label_color')
        #self.label_color_dock.setWidget(self.label_color_container)

        #load predefined files
        self.zoomWidget = ZoomWidget()
        self.colorDialog = ColorDialog(parent=self)

        self.canvas = Canvas()
        self.canvas.zoomRequest.connect(self.zoomRequest)

        scroll = QScrollArea()
        scroll.setWidget(self.canvas)
        scroll.setWidgetResizable(True)
        self.scrollBars = {
            Qt.Vertical: scroll.verticalScrollBar(),
            Qt.Horizontal: scroll.horizontalScrollBar()
        }
        
        self.canvas.scrollRequest.connect(self.scrollRequest)

        self.canvas.newShape.connect(self.newShape)  # 设置回调函数
        self.canvas.newLines.connect(self.newLines)  # 设置回调函数
        self.canvas.shapeMoved.connect(self.setDirty)
        self.canvas.selectionChanged.connect(self.shapeSelectionChanged)
        self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive)

        self.setCentralWidget(scroll)
        #self.addDockWidget(Qt.RightDockWidgetArea, self.dock)
        
        # add label color dock
        #self.addDockWidget(Qt.RightDockWidgetArea, self.label_color_dock)
        
        # add file list and dock to move faster
        #self.addDockWidget(Qt.RightDockWidgetArea, self.filedock)
        
        # select label
        #self.addDockWidget(Qt.RightDockWidgetArea, self.labelSelectDock)
        #self.dockFeatures = QDockWidget.DockWidgetClosable \
        #    | QDockWidget.DockWidgetFloatable
        #self.dock.setFeatures(self.dock.features() ^ self.dockFeatures)
        
        
        # Actions
        action = partial(newAction, self)
        quit = action('&退出', self.close,
                      'Ctrl+Q', 'quit', u'退出应用')
        # open = action('&打开', self.openFile,
        #               'Ctrl+O', 'open', u'打开图像或者打开标签文件')

        opendir = action('&打开目录', self.openDir,
                         'Ctrl+u', 'open', u'打开目录')
        remote_settings = action('&打开远程数据库[no impliment]', self.setRemoteUrl,
                                 'Ctrl+m', u'set remote url')
        settings = action('设置', self.setSettings, 'Ctrl+t', u'settings')
        
        #loadOnlineImages = action(
        #    '&导入图像',
        #   self.loadOnlineImages,
        #    'Ctrl+l',
        #    icon='open',
        #    tip=u'load images')

        changeSavedir = action(
            '&改变默认保存Annotation的路径',
            self.changeSavedir,
            'Ctrl+r',
            'open',
            u'Change default saved Annotation dir')

        openAnnotation = action('&打开注释文件', self.openAnnotation,
                                'Ctrl+q', 'openAnnotation', u'Open Annotation')

        openNextImg = action('&下一个图像', self.openNextImg,
                             'Right', 'next', u'Open Next')

        openPrevImg = action('&上一个图像', self.openPrevImg,
                             'Left', 'prev', u'Open Prev')

        #save = action('&保存', self.saveFile,
        #              'Ctrl+S', 'save', u'Save labels to file', enabled=False)
        
        saveAs = action(
            '&另存为',
            self.saveFileAs,
            'Ctrl+Shift+S',
            'save-as',
            u'Save labels to a different file',
            enabled=False)
        close = action('&关闭', self.closeFile,
                       'Ctrl+W', 'close', u'Close current file')
        color1 = action('框 &线 颜色', self.chooseColor1,
                        'Ctrl+L', 'color_line', u'Choose Box line color')
        color2 = action('框 &填充 颜色', self.chooseColor2,
                        'Ctrl+Shift+L', 'color', u'Choose Box fill color')

        createMode = action(
            '创建\n形态',
            self.setCreateMode,
            'Ctrl+N',
            'new',
            u'Start drawing Boxs',
            enabled=True)
        editMode = action(
            '&编辑\n矩形框',
            self.setEditMode,
            'Ctrl+J',
            'edit',
            u'Move and edit Boxs',
            enabled=True)

        createPoint = action('标点', self.createPoint,
                        'Ctrl+N', 'new', u'Draw new Points', enabled=True)
        
        createPolygon = action(
                    '&生成\n曲线',
                    self.createPolygon,
                    'Ctrl+p',
                    icon='new',
                    tip=u'create polygon',
                    enabled=True)

        
        delete = action('计算两点距离', self.deleteSelectedShape,
                        'Delete', 'delete', u'Delete', enabled=True)
        delete1 = action('计算点到线距离', self.deleteSelectedShape,
                        'Delete1', 'delete1', u'Delete1', enabled=True)
        deletePoint = action(
            '&删除点',
            self.deletePoint,
            'Ctrl+D',
            'copy',
            u'删除点',
            enabled=True)

        deleteline = action('删除线', self.deleteline,
                    'Delete', 'delete', u'删除线', enabled=True)

        advancedMode = action(
            '&智能模式',
            self.toggleAdvancedMode,
            'Ctrl+Shift+A',
            'expert',
            u'Switch to advanced mode',
            checkable=True)

        hideAll = action('&隐藏\n形状', partial(self.togglePolygons, False),
                         'Ctrl+H', 'hide', u'Hide all Boxs',
                         enabled=True)
        showAll = action('&显示\n形态', partial(self.togglePolygons, True),
                         'Ctrl+A', 'hide', u'Show all Boxs',
                         enabled=True)

        zoom = QWidgetAction(self)
        zoom.setDefaultWidget(self.zoomWidget)
        self.zoomWidget.setWhatsThis(
            u"Zoom in or out of the image. Also accessible with"
            " %s and %s from the canvas." % (fmtShortcut("Ctrl+[-+]"),
                                             fmtShortcut("Ctrl+Wheel")))
        self.zoomWidget.setEnabled(False)

        zoomIn = action(
            '&放大',
            partial(
                self.addZoom,
                10),
            'Ctrl++',
            'zoom-in',
            u'Increase zoom level',
            enabled=False)
        zoomOut = action('&缩小', partial(self.addZoom, -10),
                         'Ctrl+-', 'zoom-out', u'Decrease zoom level', enabled=False)
        zoomOrg = action(
            '&原始大小',
            partial(
                self.setZoom,
                100),
            'Ctrl+=',
            'zoom',
            u'Zoom to original size',
            enabled=False)
        fitWindow = action('&适应窗口', self.setFitWindow,
                           'Ctrl+Z', 'fit-window', u'Zoom follows window size',
                           checkable=True, enabled=False)
        fitWidth = action(
            '&适应宽',
            self.setFitWidth,
            'Ctrl+Shift+F',
            'fit-width',
            u'Zoom follows window width',
            checkable=True,
            enabled=False)
        
        # Group zoom controls into a list for easier toggling.
        zoomActions = (
            self.zoomWidget,
            zoomIn,
            zoomOut,
            zoomOrg,
            fitWindow,
            fitWidth)
        
        # Group remote image manage
        remoteActions = (#loadOnlineImages,
         remote_settings)
        self.zoomMode = self.MANUAL_ZOOM
        self.scalers = {
            self.FIT_WINDOW: self.scaleFitWindow,
            self.FIT_WIDTH: self.scaleFitWidth,
            # Set to one to scale to 100% when loading files.
            self.MANUAL_ZOOM: lambda: 1,
        }

        edit = action(
            '&编辑标签',
            self.editLabel,
            'Ctrl+E',
            'edit',
            u'Modify the label of the selected Box',
            enabled=True)

        search = action(
            '&搜索图片',
            self.searchLabel,
            'Ctrl+F',
            'search',
            u'搜索图片',
            enabled=True)
        #self.editButton.setDefaultAction(edit)

        shapeLineColor = action(
            '&形态 边界线颜色',
            self.chshapeLineColor,
            icon='color_line',
            tip=u'Change the line color for this specific shape',
            enabled=False)
        shapeFillColor = action(
            '&形态填充颜色',
            self.chshapeFillColor,
            icon='color',
            tip=u'Change the fill color for this specific shape',
            enabled=False)


        #labels = self.dock.toggleViewAction()
        #labels.setText('显示/因此标签面板')
        #labels.setShortcut('Ctrl+Shift+L')

        #Label list context menu.
        labelMenu = QMenu()
        addActions(labelMenu, (edit, delete))
        
        #self.pointList.setContextMenuPolicy(Qt.CustomContextMenu)
        #self.pointList.customContextMenuRequested.connect(
        #    self.popLabelListMenu)

        # Store actions for further handling.
        self.actions = struct(
            #save=save,
            saveAs=saveAs,
            #open=open,
            close=close,
            lineColor=color1,
            fillColor=color2,
            remote_mode=(),
                #loadOnlineImages,
                #loadOnlineImages),
            createPoint=createPoint,
            delete=delete,
            edit=edit,
            deletePoint=deletePoint,
            createPolygon=createPolygon,
            createMode=createMode,
            editMode=editMode,
            advancedMode=advancedMode,
            shapeLineColor=shapeLineColor,
            shapeFillColor=shapeFillColor,
            zoom=zoom,
            zoomIn=zoomIn,
            zoomOut=zoomOut,
            zoomOrg=zoomOrg,
            fitWindow=fitWindow,
            fitWidth=fitWidth,
            zoomActions=zoomActions,
            
            fileMenuActions=(
                #open,
                opendir,
                #save,
                saveAs,
                close,
                quit),
            beginner=(),
            advanced=(),
            editMenu=(
                search,
                edit,
                deletePoint,
                delete,
                None,
                color1,
                color2),
            
            beginnerContext=(
                #createRect,
                #createPolygon,
                edit,
                deletePoint,
                deleteline,
                delete),
            
            advancedContext=(
                createMode,
                createPolygon,
                editMode,
                edit,
                deletePoint,
                delete,
                shapeLineColor,
                shapeFillColor),
            onLoadActive=(
                close,
            ),
            onDETActive =(
                createPoint,
                createPolygon,
                createMode,
                editMode
            ),
            onSEGActive =(
                createPolygon,
                createMode,
                editMode
            ),
            onCLSActive =(

            ),
            onShapesPresent=(
                saveAs,
                hideAll,
                showAll))

        #tool menus settings
        self.menus = struct(
            file = self.menu('&文件'),
            edit = self.menu('&编辑'),
            view = self.menu('&视图'),
            #help = self.menu('&帮助 and 版权'),
            #login_win = self.menu('&登录'), # 登录
            recentFiles=QMenu('&打开最近'),
            labelList=labelMenu)
        for item in self.actions.remote_mode:
            item.setEnabled(False)
        
        addActions(
            self.menus.file,
            (#open,
             opendir,
             changeSavedir,
             openAnnotation,
             self.menus.recentFiles,
             #save,
             saveAs,
             remote_settings,
             settings,
             close,
             None,
             quit))
        #addActions(self.menus.help, (help,))
        
        login_win = action('&登录', self.loginWindow,
                         '', 'login', u'', enabled=True)
        #addActions(self.menus.login_win, (login_win,))
        
        addActions(self.menus.view, ( # labels,
            advancedMode,None,
            hideAll, showAll, None,
            zoomIn, zoomOut, zoomOrg, None,
            fitWindow, fitWidth))

        self.menus.file.aboutToShow.connect(self.updateFileMenu)

        # Custom context menu for the canvas widget:
        addActions(self.canvas.menus[0], self.actions.beginnerContext)
        addActions(self.canvas.menus[1], (
            action('&复制这里', self.copyShape),
            action('&移动这里', self.moveShape)))

        self.tools = self.toolbar('工具')
        self.actions.beginner = (
            #loadOnlineImages,
            #open,
            opendir,
            openNextImg,
            openPrevImg,
            #save,
            None,
            createPoint,
            createPolygon,
            deletePoint,
            delete,
            None,
            zoomIn,
            zoom,
            zoomOut,
            fitWindow,
            fitWidth)

        self.actions.advanced = (
            open, 
            #save,
            None,
            createMode, editMode, None,
            hideAll, showAll)
        self.statusBar().showMessage('%s started.' % __appname__)
        self.statusBar().show()

        # Application state.
        self.image = QImage()
        self.filename = filename
        self.recentFiles = []
        self.maxRecent = 7
        self.lineColor = None
        self.fillColor = None
        self.zoom_level = 100
        self.fit_window = False
        self.remoteMode = False
        self.app_settings = APPSettings()
        self.app_settings.load()
        settings = self.app_settings
        
        ## Fix the compatible issue for qt4 and qt5. Convert the QStringList to python list
        if settings.get(SETTING_RECENT_FILES):
            if have_qstring():
                recentFileQStringList = settings.get(SETTING_RECENT_FILES)
                self.recentFiles = [ustr(i) for i in recentFileQStringList]
            else:
                self.recentFiles = recentFileQStringList = settings.get(SETTING_RECENT_FILES)

        size = settings.get(SETTING_WIN_SIZE, QSize(600, 500))
        position = settings.get(SETTING_WIN_POSE, QPoint(0, 0))
        self.resize(size)
        self.move(position)
        saveDir = ustr(settings.get(SETTING_SAVE_DIR, None))
        self.lastOpenDir = ustr(settings.get(SETTING_LAST_OPEN_DIR, None))
        if saveDir is not None and os.path.exists(saveDir):
            self.defaultSaveDir = saveDir
            self.statusBar().showMessage('%s started. Annotation will be saved to %s' %
                                         (__appname__, self.defaultSaveDir))
            self.statusBar().show()

        # or simply:
        # self.restoreGeometry(settings[SETTING_WIN_GEOMETRY]
        self.restoreState(settings.get(SETTING_WIN_STATE, QByteArray()))
        self.lineColor = QColor(settings.get(SETTING_LINE_COLOR, Shape.line_color))
        self.fillColor = QColor(settings.get(SETTING_FILL_COLOR, Shape.fill_color))
        Shape.line_color = self.lineColor
        Shape.fill_color = self.fillColor
        

        
        # Add chris
        
        def xbool(x):
            if isinstance(x, QVariant):
                return x.toBool()
            return bool(x)

        if xbool(settings.get(SETTING_ADVANCE_MODE, False)):
            self.actions.advancedMode.setChecked(True)
            self.toggleAdvancedMode()

        # Populate the File menu dynamically.
        self.updateFileMenu()
        # Since loading the file may take some time, make sure it runs in the
        # background.
        self.queueEvent(partial(self.loadFile, self.filename))
        # self.queueEvent(partial(self.load_label_color_map))
        #if self.has_defined_color_map and len(
        #        self.label_color_map) < len(
        #        self.labelHist):
        #    print(
        #        'the num of color is less than labels, please add some color into data/label_color_map.txt')
        # Callbacks:
        self.zoomWidget.valueChanged.connect(self.paintCanvas)
        self.populateModeActions()


    def searchshowMessage(self):
        wen = self.searchLab.text()
        items = self.table.findItems(wen, QtCore.Qt.MatchExactly)
        for r in range(self.rows):       
            for c in range(self.cols):            
                self.table.item(r, c).setBackground(QBrush(QColor(255, 255, 255)))
            
        if items:
            if len(items) > 0:
                for item in items:
                    item.setBackground(QBrush(QColor(0, 255, 0)))
                    #item.setForeground(QBrush(QColor(255, 0, 0)))           
        else:
            QMessageBox.information(self, "提示", "您所搜索的内容不在表格中！")

    def myListWidgetContext(self,position):
        print('def myListWidgetContext(self,position):')
        #弹出菜单
        popMenu = QMenu()
        delAct =QAction("删除点",self)
        #查看右键时是否在item上面,如果不在.就不显示删除和修改.
        if self.pointList.itemAt(position):
            popMenu.addAction(delAct)
        delAct.triggered.connect(self.DeleteItem)
        popMenu.exec_(self.pointList.mapToGlobal(position))
        
        #assert (len(self.itemsToShapes) == len(self.pointList))
    
    #删除分组
    def DeleteItem(self):
        print('def DeleteItem(self):')
        print('begin*********************')
        print(len(self.itemsToShapes))
        print(len(self.pointList))
        print(len(self.Images[self.filename].points))
        item = self.currentItem()
        index = self.itemsToShapes[item]
        #print(index)
        #print(self.Images[self.filename].points[index])
        pop_obj = self.itemsToShapes.pop(item)
        #del self.Images[self.filename].points[index]
        self.Images[self.filename].points[index] = QPoint(-1, -1)
        self.pointList.takeItem(self.pointList.currentRow())
        print('end***************************')
        print(len(self.itemsToShapes))
        print(len(self.pointList))
        print(len(self.Images[self.filename].points))
        self.canvas.update()

    # infomation display
    def info_display(self):
        self.dowload_image_num = len(self.mImgList)
        info = 'server image num:\t' + str(self.server_image_num) + '\n' \
               + 'dowload image num:\t' + str(self.dowload_image_num) + '\n' \
               + 'precessed image num:\t' + str(self.process_image_num)
        self.info_txt.setText(info)

    ## Support Functions ##
    def createPolygon(self):
        if self.filename is None:
            return
        print('def createPolygon(self):')
        self.canvas.stop = True
        self.actions.createPoint.setEnabled(False)
        self.actions.createPolygon.setEnabled(False)
        self.canvas.linestop = False
        self.canvas.linePointsIndex = []
        print('self.labelHist', self.labelHist)
        print('self.label_fre_dic', self.label_fre_dic)
        self.labelDialog = LabelDialog(
            parent=self,
            listItem=self.labelHist,
            label_fre_dic=self.label_fre_dic)
        text = self.labelDialog.popUp()
        text = str(text)
        print('createPolygon text: ', text)
        if text == '0-不拟合':
            print('0一次样条曲线')
            self.canvas.lineType = 0
        if text == '1-一次样条曲线':
            print('1-一次样条曲线')
            self.canvas.lineType = 1
        elif text == '2-二次样条曲线':
            print('2-二次样条曲线')
            self.canvas.lineType = 2
        elif text == '3-三次样条曲线':
            print('3-三次样条曲线')
            self.canvas.lineType = 3
        elif text == '4-四次样条曲线':
            print('4-四次样条曲线')
            self.canvas.lineType = 4
        elif text == '5-五次样条曲线':
            print('5-五次样条曲线')
            self.canvas.lineType = 5
        elif text == '6-六次样条曲线':
            print('6-六次样条曲线')
            self.canvas.lineType = 6
        elif text == '8-八次样条曲线':
            print('8-八次样条曲线')
            self.canvas.lineType = 8
        elif text == '10-十次样条曲线':
            print('10-十次样条曲线')
            self.canvas.lineType = 10
        elif text == '12-十二次样条曲线':
            print('12-十二次样条曲线')
            self.canvas.lineType = 12
        elif text == '14-十四次样条曲线':
            print('14-十四次样条曲线')
            self.canvas.lineType = 14
        elif text == '16-十六次样条曲线':
            print('16-十六次样条曲线')
            self.canvas.lineType = 16
        
        pass
    
    def newLines(self):
        for key,val in enumerate(self.Images[self.filename].lineToPoint):
            if len(val.value) < 3:
                del self.Images[self.filename].lineToPoint[key]
        
        if len(self.Images[self.filename].lineToPoint) == 0:
            return

        #for key, val in enumerate(self.Images[self.filename].lineToPoint):
            #print(str(val.key) +':'+ str(val.value))
        self.db.insert_line(self.filename, self.Images[self.filename].lineToPoint[-1].key,  self.Images[self.filename].lineToPoint[-1].value)
        
        print('def newLines():')

        self.actions.createPoint.setEnabled(True)
        self.actions.createPolygon.setEnabled(True)
        self.canvas.linestop = True
        self.canvas.stop = True
        print('self.canvas.update()')
        self.canvas.update()
        return
        
        res = self.db.select_point(self.filename)
        if len(res) == 0:
            self.Images[self.filename].points = []
        else:
            self.Images[self.filename].points = []
            for index, val in enumerate(res):
                #print('index: ', index)
                self.Images[self.filename].points.append(myPoint(val["key"], QPoint(int(val["point"][0]), int(val["point"][1]))))

        res = self.db.select_line(self.filename)
        if len(res) == 0:
            self.Images[self.filename].lineToPoint = []
        else:
            self.Images[self.filename].lineToPoint = []
            for index, val in enumerate(res):
                self.Images[self.filename].lineToPoint.append(myLine(val["value"], val["points"]))
        #event.accept()
        self.canvas.Image = self.Images[self.filename]

        self.actions.createPoint.setEnabled(True)
        self.actions.createPolygon.setEnabled(True)
        self.canvas.linestop = True
        self.canvas.stop = True
        print('self.canvas.update()')
        self.canvas.update()
        pass

    def loadOnlineImages(self):
        if self.image_list:
            t = loadImageThread(
                self.database_url,
                self.image_list,
                self.mImgList,
                self.loadFilePath)
            loadOnlineImgMul(
                self.database_url,
                self.image_list,
                2,
                self.mImgList,
                self.loadFilePath)
            while True:
                if self.mImgList:
                    self.dirname = self.loadFilePath
                    self.openNextImg()
                    break
    def activeTaskMode(self,setting_state = None):
        if self.task_mode == 0 or self.task_mode == 1:
            if  setting_state is not None:
                self.enable_color_map = setting_state['enable_color_map']
            #self.labelSelectDock.setEnabled(False)
        elif self.task_mode == 2:
            self.actions.delete.setEnabled(True)
            #self.labelSelectDock.setEnabled(True)

    def setSettings(self):
        config = {'task_mode':self.task_mode,'label_font_size':self.label_font_size}
        settings_dialog = SettingDialog(parent=self,config = config)
        if settings_dialog.exec_():
            self.enable_color_map = settings_dialog.get_color_map_state()
            setting_state = settings_dialog.get_setting_state()
            if self.task_mode != setting_state['mode']:
                self.resetState()
                self.setClean()
            self.task_mode = setting_state['mode']
            if self.task_mode == 0:
                self.label_font_size = setting_state['label_font_size']
                Shape.label_font_size = self.label_font_size
                if self.canvas:
                    self.canvas.update()
            self.activeTaskMode(setting_state)
            self.loadPredefinedCLSClasses()
            print ('change mode to',setting_state)
        settings_dialog.destroy()
     
    
    
    def loginWindow(self):
        login_dialog = SignInDialog(parent=self)
        if login_dialog.exec_():
            is_login = login_dialog.is_login_ok()
            if is_login:
                pass # 计划加入Cookie， 暂时没有实现
        login_dialog.destroy()
    
    
    
    def setRemoteUrl(self):
        setRemoteUrldialog = RemoteDialog.SetRemoteDialog(parent=self)
        try:
            if setRemoteUrldialog.exec_():
                self.database_url = 'http://' + setRemoteUrldialog.get_remote_url()
                self.remoteMode = setRemoteUrldialog.is_in_remote_mode()
                self.dowload_thread_num = setRemoteUrldialog.get_thread_num()
                self.server_image_list = setRemoteUrldialog.get_server_image_list()
        except:
            print("over")
        setRemoteUrldialog.destroy()
        print (self.database_url)
        if not os.path.exists(self.loadFilePath):
            os.makedirs(self.loadFilePath)
        if self.database_url:
            try:
                image_file = requests.get(
                    self.database_url + self.server_image_list)
            except requests.URLRequired as e:
                logging.error('can not get the server image list')
                return

            self.image_list = image_file.content.split('\n')[0:-1]
            self.server_image_num = len(self.image_list)
            if self.image_list:
                self.connect_remote_db = True
                self.toggleRemoteMode()

    def noShapes(self):
        return not self.itemsToShapes
    def toggleDETMode(self, value = True):
        pass


    def toggleAdvancedMode(self, value=True):
        self._beginner = not value
        self.canvas.setEditing(True)
        self.populateModeActions()
        self.editButton.setVisible(not value)
        if value:
            self.actions.createMode.setEnabled(True)
            self.actions.editMode.setEnabled(False)
#            self.actions.remotemode
            self.dock.setFeatures(self.dock.features() | self.dockFeatures)
        else:
            self.dock.setFeatures(self.dock.features() ^ self.dockFeatures)

    def toggleRemoteMode(self):
        for item in self.actions.remote_mode:
            item.setEnabled(True)

    def fileitemDoubleClicked(self, item=None):
        currIndex = self.mImgList.index(str(item.text()))
        if currIndex < len(self.mImgList):
            filename = self.mImgList[currIndex]
            if filename:
                self.loadFile(filename)
        self.newShape()
    
    def labelColorDoubleClicked(self):
        # double clicked call back function
        pass
    
    def addCLSLabel(self,label):
        self.currentItemLabels.append(label)
        item = HashableQListWidgetItem.HashableQListWidgetItem(label)
        item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
        item.setCheckState(Qt.Checked)
        self.pointList.addItem(item)
        self.itemsToShapes[item] = label
        self.shapesToItems[label] = item
        self.pointList.addItem(item)
        self.setDirty()
    
    def labelitemDoubleClicked(self, item=None):
        if item:
            label = str(item.text())
            if label not in self.currentItemLabels:
                self.addCLSLabel(label)

    def populateModeActions(self):
        if self.beginner():
            tool, menu = self.actions.beginner, self.actions.beginnerContext
        else:
            tool, menu = self.actions.advanced, self.actions.advancedContext
        self.tools.clear()
        addActions(self.tools, tool)
        self.canvas.menus[0].clear()
        addActions(self.canvas.menus[0], menu)
        self.menus.edit.clear()
        actions = (self.actions.createPoint,) if self.beginner() \
            else (self.actions.createMode, self.actions.editMode)
        addActions(self.menus.edit, actions + self.actions.editMenu)

    def setBeginner(self):
        self.tools.clear()
        addActions(self.tools, self.actions.beginner)

    def setAdvanced(self):
        self.tools.clear()
        addActions(self.tools, self.actions.advanced)

    def setDirty(self):
        self.dirty = True
        self.actions.save.setEnabled(True)

    def setClean(self):
        return
        self.dirty = False
        self.actions.save.setEnabled(False)
        self.actions.createPoint.setEnabled(False)
        self.actions.createpolygon.setEnabled(False)

    def toggleActions(self, value=True):
        """Enable/Disable widgets which depend on an opened image."""
        for z in self.actions.zoomActions:
            z.setEnabled(value)
        for action in self.actions.onLoadActive:
            action.setEnabled(value)
        #print ('app mode', self.task_mode)

        # if self.task_mode == 0:
        #     for action in self.actions.onDETActive:
        #         action.setEnabled(value)
        # if self.task_mode == 1:
        #     for action in self.actions.onSEGActive:
        #         action.setEnabled(value)
        # if self.task_mode == 0:
        #     for action in self.actions.onCLSActive:
        #         action.setEnabled(value)

    def queueEvent(self, function):
        QTimer.singleShot(0, function)

    def status(self, message, delay=5000):
        self.statusBar().showMessage(message, delay)

    def resetState(self):
        self.itemsToShapes.clear()
        self.shapesToItems.clear()
        self.currentItemLabels = []
        self.pointList.clear()
        self.filename = None
        self.imageData = None
        self.pointsFile = None
        self.canvas.resetState()

    def currentItem(self):
        items = self.pointList.selectedItems()
        if items:
            return items[0]
        return None

    def addRecentFile(self, filename):
        if filename in self.recentFiles:
            self.recentFiles.remove(filename)
        elif len(self.recentFiles) >= self.maxRecent:
            self.recentFiles.pop()
        self.recentFiles.insert(0, filename)

    def beginner(self):
        return self._beginner

    def advanced(self):
        return not self.beginner()

    ## Callbacks ##
    def tutorial(self):
        #subprocess.Popen([self.screencastViewer, self.screencast])
        self.statusBar().showMessage("后续添加")
        pass

    def createPoint(self):
        print('标点：createPoint(self)')
        self.canvas.lintstop = True
        print(self.filename)
        if self.filename is None:
            return
        # self.shape_type = 'RECT'
        # self.canvas.set_shape_type(1)
        self.createShape()
        return


    def createShape(self):
        assert self.beginner()
        self.canvas.setEditing(False)
        self.actions.createPoint.setEnabled(False)
        self.canvas.stop = False
        #self.actions.createpolygon.setEnabled(False)

    def toggleDrawingSensitive(self, drawing=True):
        """In the middle of drawing, toggling between modes should be disabled."""
        self.actions.editMode.setEnabled(not drawing)
        if not drawing and self.beginner():
            # Cancel creation.
            print ('Cancel creation.')
            self.canvas.setEditing(True)
            self.canvas.restoreCursor()
            self.actions.createMode.setEnabled(True)
            self.actions.createpolygon.setEnabled(True)

    def toggleDrawMode(self, edit=True):
        self.canvas.setEditing(edit)
        self.actions.createMode.setEnabled(edit)
        self.actions.editMode.setEnabled(not edit)

    def setCreateMode(self):
        assert self.advanced()
        self.toggleDrawMode(False)

    def setEditMode(self):
        assert self.advanced()
        self.toggleDrawMode(True)

    def updateFileMenu(self):
        current = self.filename

        def exists(filename):
            return os.path.exists(filename)

        menu = self.menus.recentFiles
        menu.clear()
        files = [f for f in self.recentFiles if f != current and exists(f)]
        for i, f in enumerate(files):
            icon = newIcon('labels')
            action = QAction(
                icon, '&%d %s' % (i + 1, QFileInfo(f).fileName()), self)
            action.triggered.connect(partial(self.loadRecent, f))
            menu.addAction(action)

    def popLabelListMenu(self, point):
        self.menus.labelList.exec_(self.pointList.mapToGlobal(point))

    def searchLabel(self, item = None):
        text, ok=QInputDialog.getText(self, 'Text Input Dialog', '输入搜索图片的名称：')
        if ok and text:
            for key in self.Images:
                if text in key:
                    self.filename = key
                    if self.autoSaving is True and self.defaultSaveDir is not None:
                        if self.dirty is True:
                            self.saveFile()

                        if len(self.mImgList) <= 0:
                            return

                        if self.filename is None:
                            filename = self.mImgList[0]
                        else:
                            currIndex = self.mImgList.index(self.filename)
                            if currIndex < len(self.mImgList):
                                filename = self.mImgList[currIndex ]
                            else:
                                QMessageBox.about(self, "no image !",
                                                "当前目录没有该图片")
                                return
                        if filename:
                            print(filename)
                            self.loadFile(filename)
        pass

    def editLabel(self, item=None):
        print('def editLabel(self, item=None):')
        if self.canvas.hVertex is None:
            return
        print('当前编辑的点坐标索引为 : ', self.canvas.hVertex)
        index = self.canvas.hVertex
        print('点坐标为 : ', self.Images[self.filename].points[index].value.x(), self.Images[self.filename].points[index].value.y())
        width = self.image.width()
        height = self.image.height()
        print('width: ', width, 'height: ', height)

        prex = self.Images[self.filename].points[index].value.x()
        prey = self.Images[self.filename].points[index].value.y()
         #x, ok1 = QInputDialog.getInt(self, "坐标修改", "请输入x点:", prex, 0, width, 1)
        #y, ok2 = QInputDialog.getInt(self, "坐标修改", "请输入y点:", prey, 0, height, 1)
        # if ok1 and ok2:
        #     pass
        #     self.Images[self.filename].points[index] = QPoint(x, y)
        #     print('修改后的点坐标为 : ', x, y)
        label, ok1 = QInputDialog.getText(self, "坐标修改","请输入坐标值(x y):", QLineEdit.Normal, str(prex) + ' ' + str(prey))
        if ok1:
            pp = label.split()
            if len(pp) < 2:
                return
            self.Images[self.filename].points[index].value = QPoint(int(pp[0]), int(pp[1]))
            print('修改后的点坐标为 : ', pp[0], pp[0])
            self.editing = True
            self.newShape()
            self.editing = False
        return
        # TODO: construct this once
        if self.label_sub_dic:
            self.labelDialog = LabelDialog(
                parent=self,
                sub_label_items=self.label_sub_dic,
                label_fre_dic=self.label_fre_dic)
        elif len(self.labelHist) > 0:
            self.labelDialog = LabelDialog(
                parent=self,
                listItem=self.labelHist,
                label_fre_dic=self.label_fre_dic)
        if not self.canvas.editing():
            return
        item = item if item else self.currentItem()
        text = self.labelDialog.popUp(item.text())
        if text is not None:
            item.setText(text)
            self.setDirty()

    # React to canvas signals.
    def shapeSelectionChanged(self, selected=False):
        print('shapeSelectionChanged')
        self.canvas.itemToindex = -1
        if self._noSelectionSlot:
            self._noSelectionSlot = False
        else:
            shape = self.canvas.selectedShape
            if shape:
                #self.pointList.setItemSelected(self.shapesToItems[shape], True)
                pass
            else:
                self.pointList.clearSelection()
        self.actions.delete.setEnabled(selected)
        self.actions.copy.setEnabled(selected)
        self.actions.edit.setEnabled(selected)
        self.actions.shapeLineColor.setEnabled(selected)
        self.actions.shapeFillColor.setEnabled(selected)

    def addImagePoint(self):
        print("addImagePoint(self)")
        print("11212")
        
        #self.pointList.addItem(item)
        self.pointList.clear()
        self.itemsToShapes.clear()
        #print(len(self.itemsToShapes))
        #print(len(self.pointList))
        #print('*******************')
        for index, pp in enumerate(self.Images[self.filename].points):
            #print(len(self.itemsToShapes))
            #print(len(self.pointList))
            #print(self.Images[self.filename].path)
            #print(pp)
            tmp = str(pp.value.x()) + ", " + str(pp.value.y())
            #shape = self.canvas.setLastLabel(tmp)
            #print(tmp)
            item = HashableQListWidgetItem.HashableQListWidgetItem(tmp)
            self.pointList.addItem(item)
            #print(index)
            self.itemsToShapes[item] = index
            #self.itemsToShapes[item] = shape
            #self.shapesToItems[shape] = item
        #print('************************')
        #print(len(self.itemsToShapes))
        #print(len(self.pointList))
        print('self.canvas.moveing == True', self.canvas.moveing == True)
        if self.canvas.moveing == True or self.editing == True:
            index = self.canvas.hVertex
            dbpoints = []
            dbpoints.append(self.Images[self.filename].points[index].value.x())
            dbpoints.append(self.Images[self.filename].points[index].value.y())
            self.db.update_point(self.filename, index, dbpoints)
            pass
        else:
            print('assert (len(self.itemsToShapes) == len(self.pointList))')
            assert (len(self.itemsToShapes) == len(self.pointList))
            if len(self.Images[self.filename].points) == 0:
                return
            print('self.Images[self.filename].points', self.Images[self.filename].points)
            dbpoints = []
            if len(self.Images[self.filename].points) != 0:
                dbpoints.append(self.Images[self.filename].points[-1].value.x())
                dbpoints.append(self.Images[self.filename].points[-1].value.y())
            self.db.insert_point(self.filename, dbpoints)
            #res = self.db.select_point(self.filename)
            #print('插入点之后为： ', res, '当前图片： ', self.Images[self.filename].points)
            self.canvas.update()

        return 
        self.db.delete_all_point(self.filename)
        
        for p in self.Images[self.filename].points:
            dbpoints = []
            dbpoints.append(p.value.x())
            dbpoints.append(p.value.y())
            self.db.insert_point(self.filename, dbpoints)

        res = self.db.select_point(self.filename)
        #print("数据库中的点集合：", res, len(res))
        if len(res) == 0:
            self.Images[self.filename].points = []
        else:
            self.Images[self.filename].points = []
            for index, val in enumerate(res):
                #print('index: ', index)
                self.Images[self.filename].points.append(myPoint(val["key"], QPoint(int(val["point"][0]), int(val["point"][1]))))

        res = self.db.select_line(self.filename)
        #print("数据库中的线集合：", res, len(res))
        if len(res) == 0:
            self.Images[self.filename].lineToPoint = []
        else:
            self.Images[self.filename].lineToPoint = []
            for index, val in enumerate(res):
                self.Images[self.filename].lineToPoint.append(myLine(val["value"], val["points"]))
        #event.accept()
        self.canvas.Image = self.Images[self.filename]
        print('self.canvas.update()')
        print(len(self.Images[self.filename].points))
        print(len(self.canvas.Image.points))
        self.canvas.update()
        return
        
        # strdbpoints = " ".join('%s' %id for id in dbpoints)
        # print(strdbpoints)
        # self.db.updatePointsbyName(self.filename, strdbpoints)
        print('数据库更新啦！')
        self.canvas.update()
        #assert (len(self.itemsToShapes) == len(self.Images[self.filename].points))
        # for action in self.actions.onShapesPresent:
        #     action.setEnabled(True)

    def remLabel(self, shape = None,label = None):
        if self.task_mode == 0 or self.task_mode == 1:
            item = self.shapesToItems[shape]
            temp = self.pointList.takeItem(self.pointList.row(item))
            temp = None
            del self.shapesToItems[shape]
            del self.itemsToShapes[item]
        elif self.task_mode == 2:
            items = self.pointList.selectedItems()
            for item in items:
                temp = self.pointList.takeItem(self.pointList.row(item))
                temp = None
            self.currentItemLabels.remove(label)
            del self.shapesToItems[label]
            del self.itemsToShapes[item]


    def loadPoints(self):
        self.addImagePoint()
        # s = []
        # if self.task_mode == 0 or self.task_mode == 1:
        #     for label, points, line_color, fill_color, shape_type in shapes:
        #         shape = Shape(label=label, shape_type=shape_type)
        #         for x, y in points:
        #             shape.addPoint(QPointF(x, y))
        #         shape.close()
        #         if label not in self.labelHist:
        #             self.labelHist.append(label)
        #         if self.enable_color_map:
        #             shape.fill_color = self.label_color_map[
        #                     self.label_num_dic[label]]
        #         s.append(shape)
        #         self.addLabel(shape)
        #         if not self.enable_color_map:
        #             if line_color:
        #                 shape.line_color = QColor(*line_color)
        #             if fill_color:
        #                 shape.fill_color = QColor(*fill_color)
        #     self.canvas.loadShapes(s)



    def saveLabels(self, filename):
        lf = LabelFile()

        def format_shape(s):
            return dict(
                label=str(
                    s.label),
                line_color=s.line_color.getRgb() if s.line_color != self.lineColor else None,
                fill_color=s.fill_color.getRgb() if s.fill_color != self.fillColor else None,
                points=[
                    (p.x(),
                     p.y()) for p in s.points],
                shape_type=s.shape_type)

        shapes = [format_shape(shape) for shape in self.canvas.shapes]

        imgFileName = os.path.basename(self.filename)
        if self.task_mode == 1:#seg mode
            with open(os.path.join(self.defaultSaveDir,'\label_num_dic.json'), 'w') as label_num_file:
                for key in self.label_num_dic:
                    print (type(key))
                json.dump(self.label_num_dic, label_num_file)
            # the mask image will be save as file_mask.png etc.
            result_path = os.path.join(self.defaultSaveDir,os.path.splitext(imgFileName)[0],'_mask.png')
            mask_writer = label_mask_writer(
                self.label_num_dic,
                result_path,
                self.image_size[0],
                self.image_size[1])
            mask_writer.save_mask_image(shapes)
        # Can add differrent annotation formats here
        if self.task_mode == 0 or self.task_mode == 1:# seg and det mode
            try:
                if self.usingPascalVocFormat is True:
                    
                    savefilename = os.path.join(self.defaultSaveDir,os.path.splitext(imgFileName)[0],'.xml')  # the mask image will be save as file_mask.jpg etc.
                    print ('savePascalVocFommat save to:' + savefilename)
                    lf.savePascalVocFormat(
                        savefilename, self.image_size, shapes, str(
                            self.filename), shape_type_=self.shape_type)
                    self.process_image_num += 1
                else:
                    lf.save(
                        filename,
                        shapes,
                        str(
                            self.filename),
                        self.imageData,
                        self.lineColor.getRgb(),
                        self.fillColor.getRgb())
                    self.pointsFile = lf
                    self.filename = filename
                    self.process_image_num += 1
                return True
            except LabelFileError as e:
                self.errorMessage(u'Error saving label data',
                                  u'<b>%s</b>' % e)
                return False
        elif self.task_mode == 2:#cls mode
            savefilename = self.defaultSaveDir + os.path.splitext(imgFileName)[0] + '.txt' # the mask image will be save as file_mask.jpg etc.
            print (savefilename)
            with open(savefilename,'w') as outfile:
                for item in self.currentItemLabels:
                    outfile.write(item+'\n')


    def deleteline(self):
        print('def deleteLine(self):')
        if self.canvas.hVertex is None:
            return
        reply = QMessageBox.question(self, "", "是否删除连接该点的线段？", QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.db.delete_line(self.filename, self.canvas.hVertex)
            for i, val in enumerate(self.Images[self.filename].lineToPoint):
                if self.canvas.hVertex in val.value:
                    del self.Images[self.filename].lineToPoint[i]
                pass
            self.canvas.update()
            return
            res = self.db.select_point(self.filename)
            # print("数据库中的点集合：", res, len(res))
            if len(res) == 0:
                self.Images[self.filename].points = []
            else:
                self.Images[self.filename].points = []
                for index, val in enumerate(res):
                    print('index: ', index)
                    self.Images[self.filename].points.append(myPoint(val["key"], QPoint(int(val["point"][0]), int(val["point"][1]))))

            res = self.db.select_line(self.filename)
            # print("数据库中的线集合：", res, len(res))
            if len(res) == 0:
                self.Images[self.filename].lineToPoint = []
            else:
                self.Images[self.filename].lineToPoint = []
                for index, val in enumerate(res):
                    self.Images[self.filename].lineToPoint.append(myLine(val["value"], val["points"]))
            #event.accept()
            self.canvas.Image = self.Images[self.filename]
            # print('self.canvas.update()')
            # print(len(self.Images[self.filename].points))
            # print(len(self.canvas.Image.points))
            self.canvas.update()
            return

    def deletePoint(self):
        print('def deletePoint(self):')
        if self.canvas.hVertex is None:
            return
        reply = QMessageBox.question(self, "", "是否删除点？", QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            print('当前编辑的点坐标索引为 : ', self.canvas.hVertex)
            index = self.canvas.hVertex
            for key,val in enumerate(self.Images[self.filename].lineToPoint):
                if index in val.value:
                    QMessageBox.about(self,"提醒","当前点在曲线拟合当中，无法删除，请先删除线")
                    return
                        
            
            #del self.Images[self.filename].points[index]
            self.db.delete_point(self.filename, index)
            #time.sleep(0.5)
            res = self.db.select_point(self.filename)
            #print("deletePoint 数据库中的点集合：", res, len(res))
            if len(res) == 0:
                self.Images[self.filename].points = []
            else:
                self.Images[self.filename].points = []
                for index, val in enumerate(res):
                    #print('index: ', index)
                    self.Images[self.filename].points.append(myPoint(val["key"], QPoint(int(val["point"][0]), int(val["point"][1]))))

            res = self.db.select_line(self.filename)
            print("数据库中的线集合：", res, len(res))
            if len(res) == 0:
                self.Images[self.filename].lineToPoint = []
            else:
                self.Images[self.filename].lineToPoint = []
                for index, val in enumerate(res):
                    self.Images[self.filename].lineToPoint.append(myLine(val["value"], val["points"]))
            #event.accept()
            self.canvas.Image = self.Images[self.filename]
            print('self.canvas.update()')
            print(len(self.Images[self.filename].points))
            print(len(self.canvas.Image.points))
            self.canvas.update()
            return
        else:
            #event.ignore()
            return
        # print('当前编辑的点坐标索引为 : ', self.canvas.hVertex)
        # index = self.canvas.hVertex
        # print('点坐标为 : ', self.Images[self.filename].points[index].x(), self.Images[self.filename].points[index].y())
        # width = self.image.width()
        # height = self.image.height()
        # print('width: ', width, 'height: ', height)
        # prex = self.Images[self.filename].points[index].x()
        # prey = self.Images[self.filename].points[index].y()

        # #x, ok1 = QInputDialog.getInt(self, "坐标修改", "请输入x点:", prex, 0, width, 1)
        # #y, ok2 = QInputDialog.getInt(self, "坐标修改", "请输入y点:", prey, 0, height, 1)
        # # if ok1 and ok2:
        # #     pass
        # #     self.Images[self.filename].points[index] = QPoint(x, y)
        # #     print('修改后的点坐标为 : ', x, y)
        # label, ok1 = QInputDialog.getText(self, "坐标修改","请输入坐标值(x y):", QLineEdit.Normal, str(prex) + ' ' + str(prey))
        # if ok1:
        #     pp = label.split()
        #     if len(pp) < 2:
        #         return
        #     self.Images[self.filename].points[index] = QPoint(pp[0], pp[1])
        #     print('修改后的点坐标为 : ', x, y)
        
        # return
        # self.addLabel(self.canvas.copySelectedShape())
        # # fix copy and delete
        # self.shapeSelectionChanged(True)

    def pointSelectionChanged(self):
        print ('pointSelectionChanged')
        item = self.currentItem()
        print(item)
        if item:
            print('if item:')
            self.canvas.itemToindex = self.itemsToShapes[item]
        else:
            self.canvas.itemToindex = -1
        self.canvas.update()
        print('----------------------------')
        for p in self.Images[self.filename].points:
            print(p)
        if item:
            self._noSelectionSlot = True
            #print(self.itemsToShapes[item])
            #self.canvas.selectShape(self.itemsToShapes[item])
        # if self.task_mode == 0 or self.task_mode == 1:
        #     if item and self.canvas.editing():
        #         self._noSelectionSlot = True
        #         self.canvas.selectShape(self.itemsToShapes[item])
        # elif self.task_mode == 2:
        #     if item:
        #         self.selectedLabel = self.itemsToShapes[item]

    def labelItemChanged(self, item):
        shape = self.itemsToShapes[item]
        label = str(item.text())
        if label != shape.label:
            shape.label = str(item.text())
            self.setDirty()
        else:  # User probably changed item visibility
            self.canvas.setShapeVisible(shape, item.checkState() == Qt.Checked)

    # Callback functions:
    def newShape(self):
        #print('self.canvas.stop == True', self.canvas.stop == True)
        if self.canvas.stop == True and self.canvas.moveing == False and self.editing == False:
            self.actions.createPoint.setEnabled(True)
            return
        print('newShape()')
        self.addImagePoint()
        """Pop-up and give focus to the label editor.

        position MUST be in global coordinates.
        """
        # if self.label_sub_dic:
        #     self.labelDialog = LabelDialog(
        #         parent=self,
        #         sub_label_items=self.label_sub_dic,
        #         label_fre_dic=self.label_fre_dic)
        # elif len(self.labelHist) > 0:
        #     self.labelDialog = LabelDialog(
        #         parent=self,
        #         listItem=self.labelHist,
        #         label_fre_dic=self.label_fre_dic)

        # text = self.labelDialog.popUp()
        # text = str(text)
        # if text is not None:
        #     if str(text) in self.label_fre_dic:
        #         self.label_fre_dic[str(text)] += 1
        #     else:
        #         self.label_fre_dic[str(text)] = 1
        #     new_shape = self.canvas.setLastLabel(text)
        #     if self.enable_color_map:
        #         new_shape.fill_color = self.label_color_map[
        #             self.label_num_dic[text]]
        #     self.addLabel(self.canvas.setLastLabel(text))
        #     if self.beginner():  # Switch to edit mode.
        #         self.canvas.setEditing(True)
        #         self.actions.createMode.setEnabled(True)
        #         if self.task_mode == 0:
        #             self.actions.createRect.setEnabled(True)
        #         elif self.task_mode == 1:
        #             self.actions.createpolygon.setEnabled(True)
        #     else:
        #         self.actions.editMode.setEnabled(True)
        #     self.setDirty()

        #     if text not in self.labelHist:
        #         if not self.labelHist:
        #             self.label_num_dic[str(text)] = 1
        #         else:
        #             self.label_num_dic[text] = max(
        #                 self.label_num_dic.values()) + 1
        #         item = QListWidgetItem(text)
        #         self.label_color_list.addItem(item)
        #         self.labelHist.append(text)
        # else:
        #     # self.canvas.undoLastLine()
        #     self.canvas.resetAllLines()

    def scrollRequest(self, delta, orientation):
        units = - delta / (8 * 15)
        bar = self.scrollBars[orientation]
        bar.setValue(bar.value() + bar.singleStep() * units)

    def setZoom(self, value):
        self.actions.fitWidth.setChecked(False)
        self.actions.fitWindow.setChecked(False)
        self.zoomMode = self.MANUAL_ZOOM
        self.zoomWidget.setValue(value)

    def addZoom(self, increment=10):
        self.setZoom(self.zoomWidget.value() + increment)

    def zoomRequest(self, delta):
        units = delta / (8 * 15)
        scale = 10
        self.addZoom(scale * units)

    def setFitWindow(self, value=True):
        if value:
            self.actions.fitWidth.setChecked(False)
        self.zoomMode = self.FIT_WINDOW if value else self.MANUAL_ZOOM
        self.adjustScale()

    def setFitWidth(self, value=True):
        if value:
            self.actions.fitWindow.setChecked(False)
        self.zoomMode = self.FIT_WIDTH if value else self.MANUAL_ZOOM
        self.adjustScale()

    def togglePolygons(self, value):
        for item, shape in self.itemsToShapes.iteritems():
            item.setCheckState(Qt.Checked if value else Qt.Unchecked)
    def loadCLSFile(self,filepath):
        if os.path.exists(filepath):
            with open(filepath) as infile:
                lines = infile.readlines()
                for line in lines:
                    label = line.strip()
                    self.addCLSLabel(label)

    def loadFile(self, filename=None):
        """Load the specified file, or the last opened file if None."""
        self.resetState()
        self.canvas.setEnabled(False)
        if filename is None:
            if self.app_settings.get(SETTING_FILENAME):
                filename = self.app_settings[SETTING_FILENAME]
#        filename = str(filename)
        if filename and self.fileListWidget.count() > 0:
            index = self.mImgList.index(filename)
            fileWidgetItem = self.fileListWidget.item(index)
            #self.fileListWidget.setItemSelected(fileWidgetItem, True)
            fileWidgetItem.setSelected(True)
        if QFile.exists(filename):
            if LabelFile.isLabelFile(filename):
                try:
                    self.pointsFile = LabelFile(filename)
                except LabelFileError as e:
                    self.errorMessage(
                        u'Error opening file', (u"<p><b>%s</b></p>"
                                                u"<p>Make sure <i>%s</i> is a valid label file.") %
                        (e, filename))
                    self.status("Error reading %s" % filename)
                    return False
                self.imageData = self.pointsFile.imageData
                self.lineColor = QColor(*self.pointsFile.lineColor)
                self.fillColor = QColor(*self.pointsFile.fillColor)
            else:
                # Load image:
                # read data first and store for saving into label file.
                print('read data first and store for saving into label file.', filename)
                self.imageData = read(filename, None)
                self.pointsFile = None
            image = QImage.fromData(self.imageData)
            if image.isNull():
                self.errorMessage(
                    u'Error opening file',
                    u"<p>Make sure <i>%s</i> is a valid image file." %
                    filename)
                self.status("Error reading %s" % filename)
                return False
            self.status("Loaded %s" % os.path.basename(str(filename)))
            self.setWindowTitle(
                __appname__ +
                ' ' + os.path.basename(
                    str(filename)))
            self.image = image
            self.image_size = []  # image size should be clear
            self.image_size.append(image.height())
            self.image_size.append(image.width())
            self.image_size.append( 1 if image.isGrayscale() else 3)
            self.filename = filename
            #print(self.filename)
            self.canvas.loadPixmap(QPixmap.fromImage(image))
            #self.Images[self.filename].setPixmap(QPixmap.fromImage(image))
            #self.lb.setCursor(Qt.CrossCursor)
            #self.show()
            self.pixmap = QPixmap.fromImage(image)
            if self.pointsFile:
                self.loadPoints()
            self.setClean()
            self.canvas.Image = self.Images[self.filename]
            self.canvas.setEnabled(True)
            self.adjustScale(initial=True)
            self.paintCanvas()
            self.addRecentFile(self.filename)
            self.toggleActions(True)

            # Label xml file and show bound box according to its filename
            basename = os.path.basename(os.path.splitext(self.filename)[0])
            # if self.task_mode == 0 or self.task_mode == 1:
            #     if self.usingPascalVocFormat is True and \
            #             self.defaultSaveDir is not None:
            #         xmlPath = os.path.join(self.defaultSaveDir, basename + '.xml')
            #         self.loadPascalXMLByFilename(xmlPath)
            # elif self.task_mode == 2:
            #     if self.defaultSaveDir is not None:
            #         txtPath = os.path.join(self.defaultSaveDir, basename + '.txt')
            #         self.loadCLSFile(txtPath)

            return True
        return False

    def resizeEvent(self, event):
        if self.canvas and not self.image.isNull() \
                and self.zoomMode != self.MANUAL_ZOOM:
            self.adjustScale()
        super(MainWindow, self).resizeEvent(event)

    def paintCanvas(self):
        assert not self.image.isNull(), "cannot paint null image"
        self.canvas.scale = 0.01 * self.zoomWidget.value()
        self.canvas.adjustSize()
        self.canvas.update()

    def adjustScale(self, initial=False):
        value = self.scalers[self.FIT_WINDOW if initial else self.zoomMode]()
        self.zoomWidget.setValue(int(100 * value))

    def scaleFitWindow(self):
        """Figure out the size of the pixmap in order to fit the main widget."""
        e = 2.0  # So that no scrollbars are generated.
        w1 = self.centralWidget().width() - e
        h1 = self.centralWidget().height() - e
        a1 = w1 / h1
        # Calculate a new scale value based on the pixmap's aspect ratio.
        w2 = self.canvas.pixmap.width() - 0.0
        h2 = self.canvas.pixmap.height() - 0.0
        a2 = w2 / h2
        return w1 / w2 if a2 >= a1 else h1 / h2

    def scaleFitWidth(self):
        # The epsilon does not seem to work too well here.
        w = self.centralWidget().width() - 2.0
        return w / self.canvas.pixmap.width()

    def closeEvent(self, event):
        if not self.mayContinue():
            event.ignore()
        settings = self.app_settings
        # If it loads images from dir, don't load it at the begining
        if self.dirname is None:
            settings[SETTING_FILENAME] = self.filePath if self.filePath else ''
        else:
            settings[SETTING_FILENAME] = ''

        settings[SETTING_WIN_SIZE] = self.size()
        #settings[SETTING_TASK_MODE] = self.task_mode
        settings[SETTING_LABEL_FONT_SIZE] = self.label_font_size
        settings[SETTING_WIN_POSE] = self.pos()
        settings[SETTING_WIN_STATE] = self.saveState()
        settings[SETTING_LINE_COLOR] = self.lineColor
        settings[SETTING_FILL_COLOR] = self.fillColor
        settings[SETTING_RECENT_FILES] = self.recentFiles
        settings[SETTING_ADVANCE_MODE] = not self._beginner
        if self.defaultSaveDir is not None and len(self.defaultSaveDir) > 1:
            settings[SETTING_SAVE_DIR] = ustr(self.defaultSaveDir)
        else:
            settings[SETTING_SAVE_DIR] = ""

        if self.lastOpenDir is not None and len(self.lastOpenDir) > 1:
            settings[SETTING_LAST_OPEN_DIR] = self.lastOpenDir
        else:
            settings[SETTING_LAST_OPEN_DIR] = ""
        settings.save()

    ## User Dialogs ##

    def loadRecent(self, filename):
        if self.mayContinue():
            self.loadFile(filename)

    def scanAllImages(self, folderPath):
        extensions = ['.jpeg', '.jpg', '.png', '.bmp', '.JPG']
        images = []

        for root, dirs, files in os.walk(folderPath):
            for file in files:
                if file.lower().endswith(tuple(extensions)):
                    relatviePath = os.path.join(root, file)
                    images.append(os.path.abspath(relatviePath))
        images.sort(key=lambda x: x.lower())
        return images

    def changeSavedir(self, _value=False):
        if self.defaultSaveDir is not None:
            path = str(self.defaultSaveDir)
        else:
            path = '.'

        dirpath = str(
            QFileDialog.getExistingDirectory(
                self,
                '%s - Save to the directory' %
                __appname__,
                path,
                QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks))

        if dirpath is not None and len(dirpath) > 1:
            self.defaultSaveDir = dirpath

        self.statusBar().showMessage(
            '%s . Annotation will be saved to %s' %
            ('Change saved folder', self.defaultSaveDir))
        self.statusBar().show()

    def openAnnotation(self, _value=False):
        if self.filename is None:
            return

        path = os.path.dirname(str(self.filename)) \
            if self.filename else '.'
        if self.usingPascalVocFormat:
            formats = ['*.%s' % str(fmt).lower()
                       for fmt in QImageReader.supportedImageFormats()]
            filters = "Open Annotation XML file (%s)" % \
                      ' '.join(formats + ['*.xml'])
            filename = str(
                QFileDialog.getOpenFileName(
                    self, '%s - Choose a xml file' %
                    __appname__, path, filters))
            self.loadPascalXMLByFilename(filename)

    def openDir(self, _value=False):
        '''
        the default save files is orgnized as fellow:
        image_file:
                  image_file1:
                  image_file2:
                  ...
        Annotation:
                   image_file1:
                   image_file2:
                   ...
        :param _value:
        :return:
        '''
        if not self.mayContinue():
            return

        path = os.path.dirname(str(self.filename)) \
            if self.filename else '.'

        if self.lastOpenDir is not None and len(self.lastOpenDir) > 1:
            path = self.lastOpenDir

        dirpath = str(
            QFileDialog.getExistingDirectory(
                self,
                '%s - Open Directory' %
                __appname__,
                path,
                QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks))

        if dirpath is not None and len(dirpath) > 1:
            self.lastOpenDir = dirpath

        self.dirname = dirpath
        if '/' in dirpath:
            path_elem = dirpath.split('/')[:-2]
            last_path_elem = dirpath.split('/')[-1]
            s = '/'
            self.defaultSaveDir = s.join(
                path_elem) + '/Annotation' + '/' + last_path_elem + '/'
            if not os.path.exists(self.defaultSaveDir):
                os.makedirs(self.defaultSaveDir)
                # for windows
        elif '\\' in dirpath:
            path_elem = dirpath.split('\\')[:-1]
            last_path_elem = dirpath.split('\\')[-1]
            s = '\\'
            self.defaultSaveDir = s.join(
                path_elem) + '\\Annotation' + '\\' + last_path_elem + '\\'
            if not os.path.exists(self.defaultSaveDir):
                os.makedirs(self.defaultSaveDir)
        self.statusBar().showMessage(
            '%s . Annotation will be saved to %s' %
            ('Change saved folder', self.defaultSaveDir))
        self.statusBar().show()
        self.mImgList = self.scanAllImages(dirpath)
        print('图片数量为： ', len(self.mImgList))
        self.filename = None
        for imgPath in self.mImgList:
            item = QListWidgetItem(imgPath)
            self.fileListWidget.addItem(item)
            self.Images[imgPath] = Image(imgPath, self.image)
        self.openNextImg()
        for key,value in self.Images.items():
            print('{key}:{value}'.format(key = key, value = value.path))
            self.db.insert(value.path, value.image)
            res = self.db.select_point(value.path)
            #   [ {"key":0,"point":[x,y]}, {"key":1,"point":[x,y]} ]
            # print(res[0]["point"][0])
            if res is None:
                continue
            #print("数据库中的点集合：", res)
            for index, val in enumerate(res):
                self.Images[key].points.append(myPoint(val["key"], QPoint(int(val["point"][0]), int(val["point"][1]))))

            res = self.db.select_line(value.path)
            if res is None:
                continue
            #print("数据库中的线集合：", res)
            for index, val in enumerate(res):
                self.Images[key].lineToPoint.append(myLine(val["value"], val["points"]))
            

    def openPrevImg(self, _value=False):
        if self.autoSaving is True and self.defaultSaveDir is not None:
            if self.dirty is True and self.hasLabels():
                self.saveFile()
        #if not self.mayContinue():
        #    return

        if len(self.mImgList) <= 0:
            return

        if self.filename is None:
            return

        currIndex = self.mImgList.index(self.filename)
        if currIndex - 1 >= 0:
            filename = self.mImgList[currIndex - 1]
            if filename:
                self.loadFile(filename)

    def openNextImg(self, _value=False):
        # Proceding next image without dialog if having any label
        if self.autoSaving is True and self.defaultSaveDir is not None:
            if self.dirty is True:
                self.saveFile()

       # if not self.mayContinue():
        #    return

        if len(self.mImgList) <= 0:
            return

        if self.filename is None:
            filename = self.mImgList[0]
        else:
            currIndex = self.mImgList.index(self.filename)
            if currIndex+1 < len(self.mImgList):
                filename = self.mImgList[currIndex+1]
            else:
                QMessageBox.about(self, "no more images !",
                                  "this is the last image")
                return
        if filename:
            print(filename)
            self.loadFile(filename)

    def openFile(self, _value=False):
        #print('openFile')
        if not self.mayContinue():
            return
        path = os.path.dirname(str(self.filename)) \
            if self.filename else '.'
        formats = ['*.%s' % str(fmt).lower()
                   for fmt in QImageReader.supportedImageFormats()]
        if '*.jpg' not in formats:
            formats.append('*.jpg')
        if '*.jpeg' not in formats:
            formats.append('*.jpeg')
        filters = "Image & Label files (%s)" % \
                  ' '.join(formats + ['*%s' % LabelFile.suffix])
        filename, filetype = \
            QFileDialog.getOpenFileName(
                self, '%s - Choose Image or Label file' %
                __appname__, path, filters)
        #print(filename)
        if filename:
            self.loadFile(filename)

    def saveFile(self, _value=False):
        assert not self.image.isNull(), "cannot save empty image"
        if self.hasLabels():
            if self.defaultSaveDir is not None and len(
                    str(self.defaultSaveDir)):
                print ('handle the image:' + self.filename)
                self._saveFile(self.filename)
            else:
                self._saveFile(self.filename if self.pointsFile
                               else self.saveFileDialog())
        else:
            imgFileName = os.path.basename(self.filename)
            if self.task_mode == 0 or self.task_mode == 1:
                savedFileName = os.path.splitext(
                imgFileName)[0] + LabelFile.suffix
            elif self.task_mode == 2:
                savedFileName = os.path.splitext(
                imgFileName)[0] + '.txt'
            savedPath = os.path.join(
            str(self.defaultSaveDir), savedFileName)
            if os.path.isfile(savedPath):
                os.remove(savedPath)

    def saveFileAs(self, _value=False):
        assert not self.image.isNull(), "cannot save empty image"
        if self.hasLabels():
            self._saveFile(self.saveFileDialog())

    def saveFileDialog(self):
        caption = '%s - Choose File' % __appname__
        filters = 'File (*%s)' % LabelFile.suffix
        openDialogPath = self.currentPath()
        dlg = QFileDialog(self, caption, openDialogPath, filters)
        dlg.setDefaultSuffix(LabelFile.suffix[1:])
        dlg.setAcceptMode(QFileDialog.AcceptSave)
        dlg.setConfirmOverwrite(True)
        filenameWithoutExtension = os.path.splitext(self.filename)[0]
        dlg.selectFile(filenameWithoutExtension)
        dlg.setOption(QFileDialog.DontUseNativeDialog, False)
        if dlg.exec_():
            return dlg.selectedFiles()[0]
        return ''

    def _saveFile(self, filename):
        if filename and self.saveLabels(filename):
            self.addRecentFile(filename)
            self.setClean()
            self.statusBar().showMessage('Saved to  %s' % filename)
            self.statusBar().show()

    def closeFile(self, _value=False):
        if not self.mayContinue():
            return
        self.resetState()
        self.setClean()
        self.toggleActions(False)
        self.canvas.setEnabled(False)
        self.actions.saveAs.setEnabled(False)

    # Message Dialogs. #
    def hasLabels(self):
        if self.task_mode == 0 or self.task_mode == 1:
            if not self.itemsToShapes:
                # self.errorMessage(u'No objects labeled',
                # u'You must label at least one object to save the file.')
                return False
            return True
        elif self.task_mode == 2:
            if not self.currentItemLabels:
                return False
            return True

    def mayContinue(self):
        return not (self.dirty and not self.discardChangesDialog())

    def discardChangesDialog(self):
        yes, no = QMessageBox.Yes, QMessageBox.No
        msg = u'You have unsaved changes, proceed anyway?'
        return yes == QMessageBox.warning(self, u'Attention', msg, yes | no)

    def errorMessage(self, title, message):
        return QMessageBox.critical(self, title,
                                    '<p><b>%s</b></p>%s' % (title, message))

    def currentPath(self):
        return os.path.dirname(str(self.filename)
                               ) if self.filename else '.'

    def chooseColor1(self):
        color = self.colorDialog.getColor(self.lineColor, u'Choose line color',
                                          default=DEFAULT_LINE_COLOR)
        if color:
            self.lineColor = color
            # Change the color for all shape lines:
            Shape.line_color = self.lineColor
            self.canvas.update()
            self.setDirty()

    def chooseColor2(self):
        color = self.colorDialog.getColor(self.fillColor, u'Choose fill color',
                                          default=DEFAULT_FILL_COLOR)
        if color:
            self.fillColor = color
            Shape.fill_color = self.fillColor
            self.canvas.update()
            self.setDirty()

    def deleteSelectedShape(self):
        yes, no = QMessageBox.Yes, QMessageBox.No
        msg = u'You are about to permanently delete this Box, proceed anyway?'
        if yes == QMessageBox.warning(self, u'Attention', msg, yes | no):
            self.remLabel(shape=self.canvas.deleteSelected(),label=self.selectedLabel)
            self.setDirty()
            if self.noShapes():
                for action in self.actions.onShapesPresent:
                    action.setEnabled(False)

    def chshapeLineColor(self):
        color = self.colorDialog.getColor(self.lineColor, u'Choose line color',
                                          default=DEFAULT_LINE_COLOR)
        if color:
            self.canvas.selectedShape.line_color = color
            self.canvas.update()
            self.setDirty()

    def chshapeFillColor(self):
        color = self.colorDialog.getColor(self.fillColor, u'Choose fill color',
                                          default=DEFAULT_FILL_COLOR)
        if color:
            self.canvas.selectedShape.fill_color = color
            self.canvas.update()
            self.setDirty()

    def copyShape(self):
        self.canvas.endMove(copy=True)
        self.addLabel(self.canvas.selectedShape)
        self.setDirty()

    def moveShape(self):
        self.canvas.endMove(copy=False)
        self.setDirty()


    def load_label_color_map(self):
        if not self.label_color_map:
            self.label_color_map = []
        if self.label_color_map_path is None:
            self.label_color_map_path = os.path.join(
                'data', 'label_color_map.txt')
        if os.path.exists(self.label_color_map_path):
            with open(self.label_color_map_path, 'r') as f:
                lines = f.readlines()
                print ('color map', lines)
                for line in lines:
                    line = line.strip()
                    line = line.split(',')
                    line = [int(num) for num in line]
                    # RGBA
                    if len(line) == 4:
                        self.label_color_map.append(
                            QColor(line[0], line[1], line[2], line[3]))
                    elif len(line) == 3:
                        self.label_color_map.append(
                            QColor(line[0], line[1], line[2], 128))
                    else:
                        print('the num of color is wrong')
                self.has_defined_color_map = True
                print(self.label_color_map)
    
    def loadPredefinedCLSClasses(self):
        self.labelHist = []
        predefined_classes_path = os.path.join(
            'data','predefined_cls_classes.txt'
        )
        if os.path.exists(predefined_classes_path) is True:
            with open(predefined_classes_path,'r') as f:
                lines = f.readlines()
                for line in lines:
                    line = line.strip()
                    if self.labelHist is None:
                        self.lablHist = [line]
                    else:
                        self.labelHist.append(line)
        if self.labelHist:
            num = 0
            assert len(
                self.labelHist) <= 255, 'the num of labels should be less than 255 '
            for label in self.labelHist:
                # label - index
                self.label_num_dic[label] = num
                num += 1
        #add label to widget
        for cls_label in self.labelHist:
            item = QListWidgetItem(cls_label)
            self.pointListWidget.addItem(item)
            #self.pointListWidget.addItem(item)


    def loadPredefinedDETClasses(self):
        self.labelHist = []
        predefined_classes_path = os.path.join(
            'data', 'predefined_classes.txt')
        # predefined_subclasses_path = os.path.join(
        #     'data', 'predefined_sub_classes.txt')
        if os.path.exists(predefined_classes_path) is True:
            with open(predefined_classes_path,'r',encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if self.labelHist is None:
                        self.lablHist = [line]
                        self.label_fre_dic[line] = 0
                    else:
                        self.labelHist.append(line)
                        self.label_fre_dic[line] = 0
        if self.labelHist:
            num = 1
            assert len(
                self.labelHist) <= 255, 'the num of labels should be less than 255 '
            for label in self.labelHist:
                #label - color
                print('label: ', label)
                item = QListWidgetItem(str(label))
                self.label_color_list.addItem(item)
                # label - index
                self.label_num_dic[label] = num
                num += 1

    def loadPascalXMLByFilename(self, filename):
        if self.filename is None:
            return
        if os.path.exists(filename) is False:
            return

        tVocParseReader = PascalVocReader(filename)
        shapes = tVocParseReader.getShapes()
        #self.loadLabels(shapes)
        self.shape_type = tVocParseReader.getShapeType()


class Settings(object):
    """Convenience dict-like wrapper around QSettings."""

    def __init__(self, types=None):
        self.data = QSettings()
        self.types = defaultdict(lambda: QVariant, types if types else {})

    def __setitem__(self, key, value):
        t = self.types[key]
        self.data.setValue(key,
                           t(value) if not isinstance(value, t) else value)

    def __getitem__(self, key):
        return self._cast(key, self.data.value(key))

    def get(self, key, default=None):
        return self._cast(key, self.data.value(key, default))

    def _cast(self, key, value):
        # XXX: Very nasty way of converting types to QVariant methods :P
        t = self.types[key]
        if t != QVariant:
            method = getattr(QVariant, re.sub('^Q', 'to', t.__name__, count=1))
            return method(value)
        return value


def inverted(color):
    return QColor(*[255 - v for v in color.getRgb()])


def read(filename, default=None):
    try:
        with open(filename, 'rb') as f:
            return f.read()
    except:
        return default


def main(argv):
    """Standard boilerplate Qt application code."""
    app = QApplication(argv)
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    app.setApplicationName(__appname__)
    app.setWindowIcon(newIcon("app"))
    win = MainWindow(argv[1] if len(argv) == 2 else None)
    
    win.show()

    return app.exec_()




if __name__ == '__main__':
    sys.exit(main(sys.argv))
